package Functions;

import java.util.ArrayList;

import operations.FunctionOperations;

public class Secant {
	private int defaultMaxIterations = 50;
	private double defaultEpsilon = 0.00001;
	FunctionOperations myFunction;
	private int noOfIterations = 0;
	private double aprroxRoot = 0;
	private double preci = 0;
	private double aGiven = 0;
	private double bGiven = 0;

	public Secant(int max, double e) {
		defaultMaxIterations = max;
		defaultEpsilon = e;
	}

	public Secant() {
		// TODO Auto-generated constructor stub
	}

	public static double[] copy(ArrayList<Double> array) {
		double[] a = new double[array.size()];
		for (int i = 0; i < array.size(); i++) {
			a[i] = array.get(i);
		}
		return a;
	}

	public int getNoOfIts() {
		return noOfIterations;
	}

	public double errorBound() {
		ErrorBound e = new ErrorBound();
		double error = e.calculateErrorBound(noOfIterations, myFunction,
				aGiven, bGiven, aprroxRoot - preci, aprroxRoot + preci);
		return error;
	}

	public double approxRoot() {
		return aprroxRoot;
	}

	public double getPrecision() {
		return preci;
	}

	public String getInterval() {
		String x = "[" + (aprroxRoot - preci) + "," + (aprroxRoot + preci)
				+ "]";

		return x;

	}

	public double[][] secant(String function, double a, double b, double delta,
			int maxNumber) {
		aGiven = a;
		bGiven = b;
		myFunction = new FunctionOperations(function);
		ArrayList<Double> k = new ArrayList<Double>();
		ArrayList<Double> pk = new ArrayList<Double>();
		ArrayList<Double> fPk = new ArrayList<Double>();

		if (delta == -1 && maxNumber == -1) {
			new Secant();
		} else {
			defaultMaxIterations = maxNumber;
			defaultEpsilon = delta;
		}
		double precision = 1000;

		double begin = a;
		double end = b;
		k.add(0.0);
		pk.add(begin);
		double f0 = myFunction.evaluate(begin);
		double f1 = myFunction.evaluate(end);

		precision = f0;
		fPk.add(f0);

		k.add(1.0);
		if (precision > Math.abs(f1)) {
			precision = Math.abs(f1);
		}
		pk.add(end);
		fPk.add(f1);

		noOfIterations = 1;
		while (precision > defaultEpsilon
				&& noOfIterations < defaultMaxIterations) {
			double fxi = myFunction.evaluate(end);
			double fxineg1 = myFunction.evaluate(begin);
			double differenceX = end - begin;
			double differenceFx = fxi - fxineg1;
			double newValue = end - ((fxi * differenceX) / differenceFx);
			begin = end;
			end = newValue;
			double func = myFunction.evaluate(end);
			precision = Math.abs(func);
			noOfIterations++;
			k.add((double) noOfIterations);
			pk.add(end);
			fPk.add(func);

		}
		aprroxRoot = end;
		// double[][] table = new double[3][k.size()];
		// table[0] = copy(k);
		// table[1] = copy(pk);
		// table[2] = copy(fPk);
		double[][] table = new double[k.size()][3];
		double[] a1 = copy(k);
		double[] a2 = copy(pk);
		double[] a3 = copy(fPk);

		for (int i = 0; i < table.length; i++) {

			table[i][0] = a1[i];
			table[i][1] = a2[i];
			table[i][2] = a3[i];
		}
		preci = precision;
		return table;
	}

	public static void main(String[] args) {
		Secant s = new Secant();
		s.secant("5x-x*sin(x)+exp(5x)-exp(5x)+sin(x)-5sin(x)+x*sin^2(5x^2+7)",
				.0002, .05, .01, 100);
		System.out.println(s.getPrecision());
	}
}
